// Sleeping locks

#include "lock/spinlock.h"
#include "mmulayout.h"
#include "proc.h"
#include "riscv.h"
#include "type.h"

#include "lock/sleeplock.h"

#include "dbg.h"

void
sleeplock_init(sleeplock_t* lk, char* name) {
    spinlock_init(&lk->lk, "sleep lock");
    lk->name = name;
    lk->locked = 0;
    lk->pid = 0;
}

void
sleeplock_acquire(sleeplock_t* lk) {
    // __DEBUG_FUNC_START;
    spinlock_acquire(&lk->lk);
    // __DEBUG_OUTPUT("lk->lk.locked:%d\n", lk->lk.locked);
    while (lk->locked) {
        sleep_spin(lk, &lk->lk);
    }
    lk->locked = 1;
    lk->pid = getCurrentProc()->pid;
    // __DEBUG_OUTPUT("lk->lk.locked:%d\n", lk->lk.locked);
    spinlock_release(&lk->lk);
    // __DEBUG_FUNC_END;
}

void
sleeplock_release(sleeplock_t* lk) {
    // __DEBUG_FUNC_START;
    spinlock_acquire(&lk->lk);
    // __DEBUG_OUTPUT("lk->lk.locked:%d\n", lk->lk.locked);
    lk->locked = 0;
    lk->pid = 0;
    proc_wakeupSpin(lk);
    // __DEBUG_OUTPUT("lk->lk.locked:%d\n", lk->lk.locked);
    spinlock_release(&lk->lk);
    // __DEBUG_FUNC_END;
}

int
sleep_holding(sleeplock_t* lk) {
    int r;
    spinlock_acquire(&lk->lk);
    r = lk->locked && (lk->pid == getCurrentProc()->pid);
    spinlock_release(&lk->lk);
    return r;
}
